package server;

// This file contains material supporting section 10.9 of the textbook:
// "Object Oriented Software Engineering" and is issued under the open-source
// license found at www.lloseng.com

/*
 * SimpleServer.java   2001-02-08
 *
 * Copyright (c) 2000 Robert Laganiere and Timothy C. Lethbridge.
 * All Rights Reserved.
 *
 */

import db.parking.beans.Admin;
import db.parking.beans.Complaints;
import db.parking.beans.Customer;
import db.parking.beans.Orders;
import db.parking.beans.ParkingLot;
import db.tables.AdminComplaints;
import db.tables.AdminCustomer;
import db.tables.AdminManager;
import db.tables.AdminOrders;
import db.tables.AdminParking;
import db.tables.ParkingLotAdmin;

import java.util.Date;
import java.awt.List;
import java.awt.Color;
import java.sql.SQLException;
import java.sql.Timestamp;

import control.ConnectionManage;
import control.DBType;

import client.Message;

/**
 * The <code> SimpleServer </code> class is a simple subclass of the
 * <code> ocsf.server.AbstractServer </code> class. It allows testing of the
 * functionalities offered by the OCSF framework. The
 * <code> java.awt.List </code> instance is used to display informative
 * messages. This list is red when the server is closed, yellow when the server
 * is stopped and green when open.
 * 
 * @author Dr. Robert Lagani&egrave;re
 * @version February 2001
 * @see ocsf.server.AbstractServer
 */
public class SimpleServer extends AbstractServer {
	private List liste;

	// for time stamp= server current time
	long time;// = System.currentTimeMillis();
	Timestamp currTimestamp;// = new Timestamp(time);

	/**
	 * Creates a simple server. The default port is 12345.
	 * 
	 * @param liste
	 *            the liste on which information will be displayed.
	 */
	public SimpleServer(List liste) {
		super(12345);
		this.liste = liste;
	}

	/**
	 * Creates a simple server.
	 * 
	 * @param port
	 *            the port on which the server will listen.
	 * @param liste
	 *            the liste on which information will be displayed.
	 */
	public SimpleServer(int port, List liste) {
		super(port);
		this.liste = liste;
	}

	/**
	 * Hook method called each time a new client connection is accepted.
	 * 
	 * @param client
	 *            the connection connected to the client.
	 */
	synchronized protected void clientConnected(ConnectionToClient client) {
		liste.add("Client connected: " + client);
		liste.makeVisible(liste.getItemCount() - 1);
	}

	/**
	 * Hook method called each time a client disconnects.
	 * 
	 * @param client
	 *            the connection with the client.
	 */
	synchronized protected void clientDisconnected(ConnectionToClient client) {
		liste.add("Client disconnected: " + client);
		liste.makeVisible(liste.getItemCount() - 1);
	}

	/**
	 * Hook method called each time an exception is thrown in a
	 * ConnectionToClient thread.
	 * 
	 * @param client
	 *            the client that raised the exception.
	 * @param Throwable
	 *            the exception thrown.
	 */
	synchronized protected void clientException(ConnectionToClient client,
			Throwable exception) {
		liste.add("Client exception: " + exception + " with " + client);
		liste.makeVisible(liste.getItemCount() - 1);
	}

	/**
	 * Hook method called when the server stops accepting connections because an
	 * exception has been raised.
	 * 
	 * @param exception
	 *            the exception raised.
	 */
	protected void listeningException(Throwable exception) {
		liste.add("Listening exception: " + exception);
		liste.makeVisible(liste.getItemCount() - 1);
		liste.setBackground(Color.red);
	}

	/**
	 * Hook method called when the server stops accepting connections.
	 */
	protected void serverStopped() {
		liste.add("Server stopped");
		liste.makeVisible(liste.getItemCount() - 1);
		liste.setBackground(Color.yellow);
	}

	/**
	 * Hook method called when the server is clased.
	 */
	protected void serverClosed() {
		liste.add("Server closed");
		liste.makeVisible(liste.getItemCount() - 1);
		liste.setBackground(Color.red);
	}

	/**
	 * Hook method called when the server starts listening for connections.
	 */
	protected void serverStarted() {
		liste.add("Server started on port : " + this.getPort());
		liste.add("Waiting for users to connect...");
		liste.makeVisible(liste.getItemCount() - 1);
		liste.setBackground(Color.green);
	}

	/**
	 * Handles a command sent from one client to the server.
	 * 
	 * @param msg
	 *            the message sent.
	 * @param client
	 *            the connection connected to the client that sent the message.
	 */
	protected void handleMessageFromClient(Object msg, ConnectionToClient client) {

		System.out.println("server");
		ConnectionManage.getInstance().setDBType(DBType.MYSQL);

		Message tempMsg = (Message) msg;

		switch (tempMsg.getMsg()) {
		// orders handle
		case "AddOccasionalOrder":
			AddOccasionalOrder(msg);
			break;

		case "AddTemporaryOrder":
			AddTemporaryOrder(msg);
			break;

		case "AddSubscriberOrder":
			AddSubscriberOrder(msg);
			break;

		case "CancelOrder": {
			CancelOrder(msg);
			break;
		}

		case "SubmitComplaint": {
			SubmitComplaint(msg);
			break;
		}

		default:
			tempMsg.setStatus(false);
		}

		sendToAllClients(tempMsg);
	}

	/****
	 * AddOccasionalOrder**
	 * 
	 * @param msg
	 * @return void Check user validity against DB and insert an occasional user
	 */
	private void AddOccasionalOrder(Object msg) {
		Message tempMsg = (Message) msg;
		try {
			Orders o = (Orders) tempMsg.getObj();

			// check if an Occasional customer with this ID exists
			Customer bean = AdminCustomer.getRow(o.getUid(), o.getType());
			if (bean == null) {
				liste.add("ERROR:User Has Entered An Invalid ID");
				tempMsg.setStatusMsg("Such Occasional User Does Not Exist");
				return;
			}
			long time = System.currentTimeMillis();// Set current time at this
													// second to StartTime
			Timestamp currTimestamp = new Timestamp(time);
			o.setStartTime(currTimestamp);
			// check that entered leave time is not before the current time now
			if (currTimestamp.getTime() > o.getLeaveTime().getTime()) {
				liste.add("ERROR:Occaional User Has Entered Invalid Leave Time");
				tempMsg.setStatusMsg("Leave Time Must Be After Current Time");
				return;
			}
			// Check if lot if full
			ParkingLot lot = ParkingLotAdmin.getRow(o.getLotNo());
			if (lot.getTotalCars() >= lot.getCapacity()) {
				// TODO:direct client to alternative lot
				liste.add("ERROR:Parking Lot Is Full,Please Try Another Lot");
				tempMsg.setStatusMsg("Sorry,But This Parking Lot Is Full");
				return;
			}
			if (AdminOrders.insert(o)) {
				tempMsg.setStatus(true); // insert to DB was
				ParkingLotAdmin.update(o.getLotNo(), lot.getTotalCars() + 1); // update
																				// current
																				// number
																				// of
																				// cars
																				// in
																				// lot
				liste.add("Occasional Client Has Added Order No." + o.getOid());
			} else {
				tempMsg.setStatus(false);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/****
	 * AddTemporaryOrder**
	 * 
	 * @param msg
	 * @return void Check user validity against DB and insert a temporary user
	 */
	private void AddTemporaryOrder(Object msg) {
		Message tempMsg = (Message) msg;
		try {
			Orders o = (Orders) tempMsg.getObj();

			// check if an Occasional customer with this ID exists
			Customer bean = AdminCustomer.getRow(o.getUid(), o.getType());
			if (bean == null) {
				liste.add("ERROR:User Has Entered An Invalid ID");
				tempMsg.setStatusMsg("Such Temporary User Does Not Exist");
				return;
			}
			long time = System.currentTimeMillis();// Set current time at this
													// second to StartTime
			Timestamp currTimestamp = new Timestamp(time);
			o.setStartTime(currTimestamp);
			// check that entered times are after current time
			if (currTimestamp.getTime() > o.getLeaveTime().getTime()
					&& currTimestamp.getTime() > o.getStartTime().getTime()) {
				liste.add("ERROR:Temporary User Has Entered Invalid Leave Time");
				tempMsg.setStatusMsg("Times must be aftr current time");
				return;
			}
			// Check if lot if full
			ParkingLot lot = ParkingLotAdmin.getRow(o.getLotNo());

			if (lot.getTotalCars() >= lot.getCapacity()) {
				// TODO:direct client to alternative lot
				liste.add("ERROR:Parking Lot Is Full,Please Try Another Lot");
				tempMsg.setStatusMsg("Sorry,But This Parking Lot Is Full");
				return;
			}

			if (AdminOrders.insert((Orders) tempMsg.getObj())) {
				tempMsg.setStatus(true);
				ParkingLotAdmin.update(o.getLotNo(), lot.getTotalCars() + 1); // update
																				// current
																				// number
																				// of
																				// cars
																				// in
																				// lot
				liste.add("Temorary Client Has Added Order No."
						+ ((Orders) tempMsg.getObj()).getOid());
			} else {
				tempMsg.setStatus(false);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/****
	 * AddSubscriberOrder**
	 * 
	 * @param msg
	 * @return void Check user validity against DB and insert a subscribed user
	 */
	private void AddSubscriberOrder(Object msg) {
		Message tempMsg = (Message) msg;
		try {
			long time = System.currentTimeMillis();
			Timestamp currTimestamp = new Timestamp(time);
			Orders o = (Orders) tempMsg.getObj();
			o.setStartTime(currTimestamp);
			if (AdminOrders.insert((Orders) tempMsg.getObj())) {
				tempMsg.setStatus(true);
				liste.add(((Orders) tempMsg.getObj()).getType()
						+ " Subscriber Client Has Added Order No."
						+ ((Orders) tempMsg.getObj()).getOid());
			} else {
				tempMsg.setStatus(false);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/****
	 * CancelOrder**
	 * 
	 * @param msg
	 * @return void Check user validity against DB and insert a temporary user
	 */
	private void CancelOrder(Object msg) {
		// get current Timestamp of server
		long time = System.currentTimeMillis();
		Timestamp currTimestamp = new Timestamp(time);
		Message tempMsg = (Message) msg;
		Orders o = (Orders) tempMsg.getObj();
		try {
			// find the customer order by id
			int id = o.getOid();

			// check if such order exists in DB and get it
			Orders tmpOrder = new Orders();
			tmpOrder = AdminOrders.getRow(id);
			if (tmpOrder == null) {
				liste.add("ERROR:User Has Entered An Invalid Order ID");
				tempMsg.setStatus(false);
				tempMsg.setStatusMsg("You Have Entered An Invalid Order ID");
				return;
			}
			// save user scheduled parking Timestamp
			Timestamp tmpParking = tmpOrder.getStartTime();
			// check if parking is being cancelled 3 hours(108000000
			// milliseconds) before its beginning
			if (tmpParking.getTime() + 10800000 < currTimestamp.getTime()) {
				// TODO:give money back to user (compensate 100%)
			} else if ((o.getStartTime().getTime() - 108000000 < currTimestamp
					.getTime())
					&& (o.getStartTime().getTime() - 3600000 > currTimestamp
							.getTime()))
			// user has canceled Order between 1-3 hours before beginning - 50%
			// fine is given to user(1 hour = 3600000ms)
			{
				// TODO:compensate 50%
			}
			// update number of users inside lot
			ParkingLot lot = ParkingLotAdmin.getRow(o.getLotNo());
			ParkingLotAdmin.update(o.getLotNo(), lot.getTotalCars() - 1); // update
																			// current
																			// number
																			// of
																			// cars
																			// in
																			// lot
			// TODO:delete user from parking space inside lot (Parking)

			tempMsg.setStatus(true); // Order Cancellation was successful
			// TODO: tell user how much money he is getting back via Dialog
			liste.add("User has cancelled order No." + o.getOid());

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	
	
	/****
	 * SubmitComplaint**
	 * 
	 * @param msg
	 * @return void Check order validity against DB and insert a new complaint
	 */
	private void SubmitComplaint(Object msg) {
		long time = System.currentTimeMillis();		
		Timestamp currTimestamp = new Timestamp(time);
		Message tempMsg = (Message) msg;
		
		Complaints complaint=(Complaints) tempMsg.getObj();
		complaint.setTimestamp(currTimestamp);
		complaint.setStatus(0); 	//new complaint
		complaint.setAmount(0);


		int id = complaint.getOrderID();
		liste.add(toString());									
		Orders order = new Orders();
		try {
			order = AdminOrders.getRow(id); // get the order detail from data base
			complaint.setCustomerID(order.getUid());
			if (order.getType().equals("Temporary")) { // cancel only temporary

				if( complaint.getOrderID() == order.getOid()){	//there is a complaint
					AdminComplaints.insert(complaint);
					tempMsg.setStatusMsg("Your Complaint is Submitted, We will contact youas soon as possible");
					tempMsg.setStatus(true);
					liste.add("submitt complaint");
				}
				else{
					tempMsg.setStatusMsg("There Is no such Order Number:"+order.getOid());
					tempMsg.setStatus(false);
				}
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println(e.toString()+" SimpleServer->SubmitComplaint");
			liste.add(e.toString()+" SimpleServer->SubmitComplaint");
			tempMsg.setStatusMsg("There Is no such id");
			tempMsg.setStatus(false);
		}

	}

}
